package com.xd.center.http.builder;

import com.xd.center.http.authentication.HttpAuth;
import com.xd.center.http.handler.HttpHandler;
import com.xd.center.http.handler.HttpHandlerFactory;
import com.xd.center.http.handler.MethodHandler;
import com.xd.center.http.proxy.HttpProxy;
import com.xd.center.http.proxy.RestTemplateProxy;
import com.xd.center.http.proxy.ServerParam;
import lombok.Data;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedHashMap;
import java.util.Map;

@Data
public class HttpBuilder {

  private final String AUTH_INJECTION = "auth.injection";
  private final String AUTH_REFLEX = "auth.reflex";

  private ApplicationContext context;
  private Class<?> c;
  private HttpAuth httpAuth;
  private HttpContract contract;
  private HttpEncoder encoder;
  private HttpDecoder decoder;

  private RestTemplate restTemplate;
  private ServerParam serverParam;

  private HttpMethod httpMethod;
  private MediaType mediaType;
  private String url;

  private HttpBuilder() {
  }

  public static HttpBuilder init(ApplicationContext context, Class<?> c) {
    HttpBuilder httpBuilder = new HttpBuilder();
    httpBuilder.context = context;
    httpBuilder.c = c;
    httpBuilder.serverParam = (ServerParam) context.getBean("serverParam");
    httpBuilder.restTemplate = (RestTemplate) context.getBean("httpRestTemplate");

    return httpBuilder;
  }

  /**
   * 设置http基础信息
   * 调用方式(post,get),参数类型(json,form),url
   *
   * @return
   */
  public HttpBuilder contract(HttpContract contract) {
    this.contract = contract;
    return this;
  }

  public HttpBuilder encoder(HttpEncoder encoder) {
    this.encoder = encoder;
    return this;
  }

  public HttpBuilder decoder(HttpDecoder decoder) {
    this.decoder = decoder;
    return this;
  }

  public <T> T build() {
    Map<Method, MethodMetadata> methodMetadataMap = contract.parseAndValidateMetadata(c); //获取注解数据

    MethodMetadata first = null;
    for (Map.Entry<Method, MethodMetadata> entry : methodMetadataMap.entrySet()) {
      first = entry.getValue();
      if (first != null) {
        break;
      }
    }
    if (null != first) {
      if (null == serverParam.getServer() || serverParam.getServer().isEmpty()) {
        throw new RuntimeException("http-server:server配置为空，请检查配置文件是否存在");
      }
      Map<String, String> serverMap = serverParam.getServer().get(first.getServer());
      if (null!= serverMap && !serverMap.isEmpty()) {
        if (serverMap.containsKey(AUTH_INJECTION)) {
          httpAuth = (HttpAuth) context.getBean(serverMap.get(AUTH_INJECTION));
        } else if (serverMap.containsKey(AUTH_REFLEX)) {
          try {
            Class<?> httpAuthClass = Class.forName(serverMap.get(AUTH_REFLEX));
            httpAuth = (HttpAuth) httpAuthClass.getDeclaredConstructor().newInstance();
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }
    }

    Map<Method, MethodHandler> methodMap = new LinkedHashMap();
    for (Method method : c.getMethods()) {
      MethodMetadata methodMetadata = methodMetadataMap.get(method);
      methodMetadata.setHttpAuth(httpAuth);
      methodMetadata.setEncoder(encoder);
      methodMetadata.setDecoder(decoder);
      methodMetadata.setServerMap(serverParam.getServer().get(methodMetadata.getServer()));
      methodMetadata.setResultClass(method.getReturnType());
      methodMetadata.setResultType(method.getAnnotatedReturnType().getType());
      HttpProxy httpProxy = new RestTemplateProxy(restTemplate);
      methodMap.put(method, new HttpHandler(httpProxy, methodMetadata));
    }
    InvocationHandler handler = new HttpHandlerFactory.Default().create(c, methodMap);
    T proxy = (T) Proxy.newProxyInstance(c.getClassLoader(), new Class<?>[]{c}, handler);
    return proxy;
  }

}